<!--
* @Author: zhangjing
* @Date: 2025-01-13 11:30:07
* @Description: AI问答=>
-->
<template>
	<div class="pannel">
		<audio :src="audioUrl" ref="audioRef"></audio>
		<div class="cardbox flex flex-v flex-pack-center">
			<!-- <div v-if="operateType == 'nostart'">
				<div class="fixed-save-btn" :class="{ official: isPro }" @click="startAnswer">开始</div>
			</div> -->
			<div class="myForm" v-if="operateType == 'nostart' && !(isAnswering - 0)">
				<div class="flex flex-align-center flex-pack-center">
					<div class="btn" @click="startAnswer">
						<img src="/home/btn.png" alt="" />
						<span>开始</span>
					</div>
				</div>
				<div style="color: #f00">长按语音键2s后开始答题，以防收音不完整</div>
			</div>
			<div class="answer" v-else>
				<div class="txtlist">
					<div
						class="item flex"
						:class="[item && item.data && item.aiAnswer ? 'flex-align-top' : 'flex-align-center']"
						v-for="(item, index) in txtlist"
						:key="index"
					>
						<div class="avatar">{{ item.studName }}</div>
						<div class="flex-1">
							<div style="color: #f00" v-if="item.data && item.aiAnswer == ''">
								请不要提与学习无关的问题。
							</div>
							<template v-else>
								<div v-if="item && item.data" style="color: #333">{{ item.data }}</div>
								<div v-else>系统正在思考中...</div>
								<div style="font-size: 18px">
									{{ item.aiAnswer }}
								</div>
							</template>
						</div>
						<img
							v-if="item.data && item.aiAnswer"
							:src="`/audio/noticeplay.${item.play ? 'gif' : 'png'}`"
							alt=""
							srcset=""
							@click="play(item, index)"
						/>
					</div>
				</div>
				<div class="save-btn" @click="stopAnswer">结束</div>
				<div class="prevtxt" @click="prevtxtScreen" v-show="txtlist.length > 0"></div>
				<div class="nexttxt" @click="nexttxtScreen" v-show="txtlist.length > 0"></div>
			</div>
		</div>
		<!-- <div class="topicType">
			<img :src="`/impromptu${isPro ? '_pro' : ''}/topicType.png`" class="img" />
			<span class="name">AI问答</span>
		</div> -->
	</div>
</template>

<script>
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex';
import { debounce, getBytesLength, base64ToBlob, generateRandomString } from '@/utils/base.js';
//雪花字符
class Snowflake {
	constructor(workerId, datacenterId, epoch = BigInt(1577836800000)) {
		// 2020-01-01
		if (workerId > 1023n || workerId < 0n) {
			throw new Error('worker Id can only have 10 bits');
		}
		if (datacenterId > 31n || datacenterId < 0n) {
			throw new Error('datacenter Id can only have 5 bits');
		}
		this.workerId = workerId;
		this.datacenterId = datacenterId;
		this.sequence = 0n;
		this.epoch = epoch;
		this.lastTimestamp = -1n;
	}

	nextId() {
		const timestamp = BigInt(Date.now());

		if (timestamp < this.lastTimestamp) {
			throw new Error(
				`Clock moved backwards. Refusing to generate id for ${this.lastTimestamp - timestamp} milliseconds`
			);
		}

		if (timestamp === this.lastTimestamp) {
			this.sequence = (this.sequence + 1n) & 4095n; // 12 bits
			if (this.sequence === 0n) {
				timestamp = this.tilNextMillis(this.lastTimestamp);
			}
		} else {
			this.sequence = 0n;
		}

		this.lastTimestamp = timestamp;

		return ((timestamp - this.epoch) << 22n) | (this.datacenterId << 17n) | (this.workerId << 12n) | this.sequence;
	}

	tilNextMillis(lastTimestamp) {
		let timestamp = BigInt(Date.now());
		while (timestamp <= lastTimestamp) {
			timestamp = BigInt(Date.now());
		}
		return timestamp;
	}
}
const snowflake = new Snowflake(BigInt(1), BigInt(1));
import $ from '@/utils/jquery-vendor';
export default {
	name: 'speechAnswer',
	props: {
		//接收器信息
		machineData: {
			type: Object,
			default: () => {},
		},
		//表单数据
		formData: {
			type: Object,
			default: () => {},
		},
	},
	data() {
		return {
			csId: '',
			classId: '',
			operateType: 'nostart', //组件页面类型
			bidObj: {},
			txtlist: [],
			baseUrl: process.env.VUE_APP_BASE_API + '/mp3/',
			audioUrl: '',
			model: 'qwen',
		};
	},
	created() {
		let beginClassData = this.$ls.get('beginClass'); //上课数据
		this.csId = beginClassData.csId;
		this.classId = beginClassData.classId;
		if (this.isAnswering - 0) {
			this.operateType = 'answer';
		}
	},
	mounted() {
		let $me = this;
		var audio = this.$refs.audioRef;
		if (audio) {
			audio.addEventListener(
				'ended',
				function () {
					$me.txtlist.map((item) => {
						item.play = false;
					});
					$me.audioUrl = null;
				},
				false
			);
		}
	},
	computed: {
		...mapState({
			deviceType: (state) => state.websockStore.deviceType,
			studentList: (state) => state.websockStore.studentList,
			isPro: (state) => state.isPro,
			stopDeviceEventList: (state) => state.websockStore.stopDeviceEventList,
			minProjectLogin: (state) => state.minProjectStore.minProjectLogin, //小程序是否登录
			isAnswering: (state) => state.websockStore.isAnswering,
			ans_id: (state) => state.websockStore.ans_id,
		}),
		voiceStream() {
			return this.$store.getters.onEvent('voice_stream');
		},
		speechAnswer() {
			return this.$store.getters.onSpeechAnswer();
		},
		speechAnswerAI() {
			return this.$store.getters.onSpeechAnswerAI();
		},
	},
	watch: {
		voiceStream: {
			handler(newValue, oldValue) {
				if (newValue && JSON.stringify(newValue) != JSON.stringify(oldValue)) {
					console.log('this.ans_id', this.ans_id);
					if (this.ans_id == newValue.ans_id) {
						if (newValue.pac_num == 1) {
							this.bidObj[newValue.uID] = snowflake.nextId().toString();
						}
						if (this.bidObj[newValue.uID]) {
							let msg = {
								...newValue,
								bid: this.bidObj[newValue.uID],
								csId: this.formData.csId, //课题id
								ans_id: this.ans_id,
								model: this.model,
								volType: newValue.voice_type == 'speex' ? 1 : 0,
								subjCode: this.formData.subjectCode,
							};
							this.audio_RABBITMQ_SEND(JSON.stringify(msg));
						}
					}
				}
			},
			immediate: true, //初始化时让handler调用一下
			deep: true, // 开启深度监听
		},

		speechAnswer: {
			handler(newValue, oldValue) {
				if (newValue && JSON.stringify(newValue) != JSON.stringify(oldValue)) {
					//暂时不需要在答案返回前显示题目
					return false;
					if (this.ans_id == newValue.ansId) {
						if (this.studentList) {
							let stud = this.studentList.find((item) => item.machineId - 0 == newValue.uID);
							this.txtlist.push({
								...newValue,
								aiAnswer: '',
								...stud,
								play: false,
							});
							this.$nextTick(function () {
								$('.txtlist').animate(
									{
										scrollTop: $('.txtlist')[0].scrollHeight,
									},
									400
								);
							});
						}
					}
				}
			},
			immediate: true, //初始化时让handler调用一下
			deep: true, // 开启深度监听
		},
		speechAnswerAI: {
			handler(newValue, oldValue) {
				if (newValue && JSON.stringify(newValue) != JSON.stringify(oldValue)) {
					let aiAnswer = newValue.answer;
					console.log('aiAnswer', aiAnswer, aiAnswer == '""');
					if (aiAnswer == '""') {
						aiAnswer = '';
					}
					// let index = -1;

					// if (this.txtlist && this.txtlist.length > 0) {
					// 	index = this.txtlist.findIndex((item) => item.bID == newValue.bID);
					// }
					// if (index > -1) {
					// 	this.txtlist[index].aiAnswer = aiAnswer;
					// } else {

					// }
					if (this.ans_id == newValue.ansId) {
						if (this.studentList) {
							let stud = this.studentList.find((item) => item.machineId - 0 == newValue.uID);
							console.log('stud', stud);
							this.txtlist.push({
								...newValue,
								aiAnswer,
								...stud,
								play: false,
							});
							this.$nextTick(function () {
								$('.txtlist').animate(
									{
										scrollTop: $('.txtlist')[0].scrollHeight,
									},
									400
								);
							});
						}
					}
				}
			},
			immediate: true, //初始化时让handler调用一下
			deep: true, // 开启深度监听
		},
	},
	methods: {
		...mapMutations(['audio_RABBITMQ_SEND', 'WEBSOCKET_SEND', 'SET_isAnswering', 'SET_ANS_ID']),
		//去答题
		startAnswer() {
			this.curuID = '';
			/* 判断移动端正在控制PC端 */
			if (this.minProjectLogin) {
				this.$message.error('移动端正在控制PC端，不能发题！');
				return;
			}
			//发题前判断该班级是否有学生。
			if (this.studentList.length == 0) {
				let tempTestData = this.$ls.get('tempTestData');
				this.$message.error('（' + tempTestData.className + '）班级没有学生，请先添加学生！');
				return;
			}
			this.sendStartAnswer();
		},
		sendStartAnswer() {
			this.txtlist = []; //清空识别记录
			this.WEBSOCKET_SEND({
				fun: 'answer_start',
				uID: 0,
				type: 8,
			});
			this.studentList.forEach((item) => {
				console.log('item', item);
				if (item.status == 1) {
					let msg = '   ' + item.studName;
					let len = 16 - getBytesLength(msg);
					for (var i = 0; i < len; i++) {
						msg = msg + ' ';
					}
					msg = msg + '长按语音键发言';
					this.WEBSOCKET_SEND({
						fun: 'dtq_echo_set',
						uID: item.machineId - 0,
						msg: msg,
					});
				}
			});
			this.operateType = 'answer';
			this.SET_isAnswering(1);
		},
		stopAnswer() {
			this.WEBSOCKET_SEND({
				fun: 'answer_start',
				uID: 0,
				type: 128, //结束答题
			});
			this.studentList.forEach((item) => {
				if (item.status == 1) {
					let msg = '   ' + item.studName;
					this.WEBSOCKET_SEND({
						fun: 'dtq_echo_set',
						uID: item.machineId - 0,
						msg: msg,
					});
				}
			});
			this.audioList = [];
			this.curIndex = -1;
			this.curuID = '';
			this.operateType = 'nostart';
			this.SET_isAnswering(0);
			this.SET_ANS_ID('');
		},
		/* 切换语音识别上一屏 */
		prevtxtScreen() {
			this.$nextTick(function () {
				let scrollTop = $('.txtlist')[0].scrollTop;
				let offsetHeight = $('.txtlist')[0].offsetHeight;
				console.log(scrollTop);
				console.log(offsetHeight);
				$('.txtlist').animate(
					{
						scrollTop: scrollTop - offsetHeight > 0 ? scrollTop - offsetHeight : 0,
					},
					400
				);
			});
		},
		/* 切换语音识别下一屏 */
		nexttxtScreen() {
			this.$nextTick(function () {
				let scrollTop = $('.txtlist')[0].scrollTop;
				let offsetHeight = $('.txtlist')[0].offsetHeight;
				let scrollHeight = $('.txtlist')[0].scrollHeight;
				console.log(scrollTop);
				console.log(offsetHeight);
				$('.txtlist').animate(
					{
						scrollTop: scrollTop + offsetHeight > scrollHeight ? scrollHeight : scrollTop + offsetHeight,
					},
					400
				);
			});
		},
		play(info) {
			if (info.play) {
				info.play = false;
				this.$refs.audioRef.pause();
			} else {
				this.txtlist.forEach((item) => {
					item.play = false;
				});
				info.play = true;
				this.audioUrl = this.baseUrl + info.bID + '/a.mp3';
				this.$refs.audioRef.load();
				this.$nextTick(() => {
					this.$refs.audioRef.play();
				});
			}
		},
	},
};
</script>

<style lang="less" scoped>
.pannel {
	position: relative;
	width: 1162px;
	margin: 0 auto;
	height: 100%;
	// padding: 50px 0 30px;
	@media screen and (max-width: 1366px) {
		width: 1024px;
	}

	.namebar img {
		position: absolute;
		left: -20px;
		bottom: -10px;
		width: 122px;
		height: 122px;
	}
	.save-btn {
		background: @primary-color;
		width: 300px;
		height: 60px;
		line-height: 60px;
		border-radius: 40px;
		text-align: center;
		color: #fff;
		font-size: 30px;
		cursor: pointer;
		margin: 20px auto;
		position: absolute;
		bottom: 60px;
		left: 50%;
		transform: translateX(-50%);
		&.small {
			width: 100px;
			height: 40px;
			line-height: 40px;
			font-size: 18px;
			margin: 20px auto;
		}
		&:hover {
			background: rgba(0, 190, 197, 0.5);
		}
		&.official:hover {
			background: rgba(86, 151, 245, 0.5);
		}
	}
	.answer {
		height: 100%;
	}
}
/* **头部题目类型** */
.topicType {
	width: 304px;
	height: 100px;
	line-height: 100px;
	position: fixed;
	top: 0;
	left: 49px;
	z-index: 7;
	.img {
		width: 304px;
		height: 100px;
		position: absolute;
		right: 0;
	}
	.name {
		position: absolute;
		top: 70%;
		left: 50%;
		transform: translate(-50%, -50%);
		font-size: 30px;
		color: #fff;
	}
	@media screen and (max-width: 1366px) {
		width: 254px;
		height: 80px;
		line-height: 80px;
		.img {
			width: 254px;
			height: 80px;
		}
		.name {
			font-size: 28px;
		}
	}
}
.cardbox {
	overflow: visible;
	height: 100%;
	position: relative;
	margin-top: 0;
	padding-top: 15px;
}
.cardbox .closeWin {
	position: absolute;
	right: -20px;
	bottom: -16px;
	width: 46px;
	height: 46px;
	img {
		display: block;
		width: 100%;
		height: 100%;
	}
}

.fixed-save-btn {
	background: @primary-color;
	width: 247px;
	height: 40px;
	line-height: 40px;
	border-radius: 40px;
	text-align: center;
	color: #fff;
	font-size: 20px;
	font-weight: bold;
	cursor: pointer;
	position: fixed;
	bottom: 60px;
	right: 180px;
	z-index: 9;
	&:hover {
		background: rgba(0, 190, 197, 0.5);
	}
	&.official:hover {
		background: rgba(86, 151, 245, 0.5);
	}
	@media screen and (max-width: 1366px) {
		width: 227px;
	}
}
.answer {
	position: relative;
}
.txtlist {
	position: absolute;
	top: 90px;
	bottom: 160px;
	left: 0;
	right: 0;
	overflow: auto;
	.item {
		border: 4px solid @primary-color;
		border-radius: 20px;
		background: #f3f8ff;
		padding: 10px;
		margin-top: 10px;
		font-size: 24px;
		color: @primary-color;
		.avatar {
			width: 94px;
			height: 94px;
			border-radius: 100%;
			background: @primary-color;
			color: #fff;
			font-weight: bold;
			font-size: 20px;
			text-align: center;
			display: flex;
			align-items: center;
			justify-content: center;
		}
		.flex-1 {
			min-width: 0;
			margin: 0 10px;
		}
		img {
			width: 53px;
			height: 53px;
			cursor: pointer;
		}
	}
}

.prevtxt,
.nexttxt {
	position: absolute;
	bottom: 160px;
	right: -10px;
	z-index: 999;
	width: 60px;
	height: 60px;
	margin-right: -60px;
	background: @primary-color no-repeat center center;
	background-size: 40px auto;
	border-radius: 100%;
	border: 3px solid #fff;
	box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.1);
	cursor: pointer;
}

.prevtxt {
	margin-bottom: 70px;
	background-image: url(/audio/prev.png);
}

.nexttxt {
	background-image: url(/audio/next.png);
}
.myForm {
	position: fixed;
	bottom: 120px;
	left: 50%;
	transform: translate(-50%);
	font-size: 18px;
	font-weight: 700;
	z-index: 999;
	.form-item {
		& + .form-item {
			margin-top: 7px;
		}
		label {
			text-align: right;
			width: 8em;
			margin-right: 7px;
		}
		.ant-input-affix-wrapper {
			height: 40px;
		}
		.my-input {
			width: 343px;
			height: 40px;
			border: 1px solid @primary-color;
			border-radius: 23px;
			overflow: hidden;
			.ant-input-group-addon {
				background-color: #fff;
				border: none;
				border-radius: 23px;
				cursor: pointer;
			}
			.icon {
				width: 30px;
				height: auto;
			}
			input,
			.ant-input-number {
				border: none;
				height: 38px;
				border-radius: 23px;
				font-size: 15px;
				font-weight: bold;
			}
			.ant-input-number-handler-wrap {
				border-radius: 0 23px 23px 0;
			}
			.ant-select-selection {
				border: none;
				height: 38px;
				border-radius: 23px;
				font-size: 15px;
			}

			.ant-select-selection__rendered {
				line-height: 38px;
			}
		}
	}
}
.btn {
	position: relative;
	height: 60px;
	width: 60px;
	cursor: pointer;
	span {
		position: absolute;
		color: #fff;
		font-size: 12px;
		top: 50%;
		left: 50%;
		transform: translate(-35%, -50%);
		white-space: nowrap;
	}
}
</style>

<style></style>
